package com.boarsoft.rpc.util;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.boarsoft.common.util.FileUtil;

import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.NotFoundException;

public class RpcClassUtil {
	private static final Logger log = LoggerFactory.getLogger(RpcClassUtil.class);

	/** */
	private static URLClassLoader classLoader;
	/** */
	private static final ClassPool classPool = ClassPool.getDefault();
	
	static {
		// for web container such as tomcat etc
		classPool.insertClassPath(new ClassClassPath(RpcClassUtil.class));
		classPool.importPackage("com.boarsoft.rpc.core.JavassitMaker");
	}

	public static void load(String paths)
			throws ClassNotFoundException, IOException, IllegalAccessException, IllegalArgumentException,
			InvocationTargetException, NoSuchMethodException, SecurityException, NotFoundException {
		//
		Method add = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
		if (!add.isAccessible()) {
			add.setAccessible(true);
		}
		classLoader = (URLClassLoader) RpcClassUtil.class.getClassLoader();
//		classLoader = new URLClassLoader(new URL[] {}, ClassLoader.getSystemClassLoader());
		for (String p : paths.split(",")) {
			File d = new File(p);
			if (!d.exists() || !d.isDirectory() || !d.canRead()) {
				log.warn("Can not read jars from path {}", p);
				continue;
			}
			load(d, add);
			classPool.appendClassPath(d.getAbsolutePath().concat("/*"));
			// clsPool.insertClassPath(new
			// ClassClassPath(ApplicationContext.class.getClass()));
		}
		// classPool.importPackage("org.springframework.context.ApplicationContext");
		// classPool.importPackage("com.boarsoft.rpc.core.DynamicInvoker");
	}

	private static void load(File dir, Method add) throws ClassNotFoundException, IOException, IllegalAccessException,
			IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
		log.info("Load external jar from directory {}", dir.getAbsolutePath());
		List<File> libs = FileUtil.list(dir, new FileFilter() {
			@Override
			public boolean accept(File f) {
				return f.exists() && f.isFile() && f.canRead()//
						&& !f.isHidden() && f.getName().endsWith(".jar");
			}
		});
		for (File f : libs) {
			URL url = f.toURI().toURL();
			log.info("Load external jar {}", url);
			add.invoke(classLoader, url);
			try (JarFile jf = new JarFile(f)) {
				Enumeration<JarEntry> entries = jf.entries();
				while (entries.hasMoreElements()) {
					JarEntry je = entries.nextElement();
					String cn = je.getName();
					if (cn != null && cn.endsWith(".class")) {
						cn = cn.replace("/", ".").substring(0, cn.lastIndexOf("."));
						log.info("Load external class {} from {}", cn, url);
						classLoader.loadClass(cn);
					}
				}
			}
		}
	}

	public static ClassPool getClassPool() {
		return classPool;
	}
}
